<script lang='ts' setup>
import '@/assets/css/application.css'

import { onMounted, reactive } from 'vue'
import { v2ray_get_state } from '@/apis/application/v2ray/v2ray_get_state.ts'
import {
  APPLICATION_STATE_INSTALL_FAILURE,
  APPLICATION_STATE_INSTALLED,
  APPLICATION_STATE_INSTALLING,
  APPLICATION_STATE_NAMES,
  APPLICATION_STATE_RELOADING,
  APPLICATION_STATE_RESTARTING,
  APPLICATION_STATE_RUN_ERROR,
  APPLICATION_STATE_RUNNING,
  APPLICATION_STATE_STARTING,
  APPLICATION_STATE_STOPPED,
  APPLICATION_STATE_STOPPING,
  ApplicationState
} from '@/apis/application/state.ts'
import { Bound, v2ray_get_config, V2rayConfig } from '@/apis/application/v2ray/v2ray_get_config.ts'
import { v2ray_start } from '@/apis/application/v2ray/v2ray_start.ts'
import { v2ray_restart } from '@/apis/application/v2ray/v2ray_restart.ts'
import { v2ray_stop } from '@/apis/application/v2ray/v2ray_stop.ts'
import ApplicationV2rayInboundVMess from '@/components/applications/v2ray/ApplicationV2rayInboundVMess.vue'
import { new_v2ray_inbound_empty_vmess, new_v2ray_outbound_freedom, new_v2ray_outbound_vmess, V2rayInboundVMess, V2rayOutboundFreedom, V2rayOutboundVMess } from '@/apis/application/v2ray/structs.ts'
import { v2ray_remove_inbound } from '@/apis/application/v2ray/v2ray_remove_inbound.ts'
import ApplicationV2rayOutboundFreedom from '@/components/applications/v2ray/ApplicationV2rayOutboundFreedom.vue'
import { v2ray_remove_outbound } from '@/apis/application/v2ray/v2ray_remove_outbound.ts'
import ApplicationV2rayOutboundVMess from '@/components/applications/v2ray/ApplicationV2rayOutboundVMess.vue'
import ApplicationV2rayVMessQRCode from '@/components/applications/v2ray/ApplicationV2rayVMessQRCode.vue'

const state = reactive<{ id: unknown, loading: boolean, state: ApplicationState, config: V2rayConfig | undefined, starting: boolean, restarting: boolean, stopping: boolean }>({ id: null, loading: true, state: { state: 1, progress: 0, message: '', stage: '', stage_progress: 0, version: '' }, config: undefined, starting: false, restarting: false, stopping: false })
const inbounds = reactive<{ vmess: V2rayInboundVMess }>({ vmess: new_v2ray_inbound_empty_vmess() })
const outbounds = reactive<{ freedom: V2rayOutboundFreedom, vmess: V2rayOutboundVMess }>({ freedom: new_v2ray_outbound_freedom(), vmess: new_v2ray_outbound_vmess() })
const modals = reactive<{ inbound: { vmess: boolean }, outbound: { freedom: boolean, vmess: boolean }, qrcode: boolean }>({ inbound: { vmess: false }, outbound: { freedom: false, vmess: false }, qrcode: false })

onMounted(async () => {
  load().then(() => {
  })
})

async function load(): Promise<void> {
  const sr = await v2ray_get_state()
  if (0 !== sr.code) {
    state.loading = false
    window.$message.error(sr.message)

    return
  }
  state.state = sr.data

  const cr = await v2ray_get_config()
  if (0 !== cr.code) {
    window.$message.error(cr.message)

    return
  }
  state.config = cr.data

  if (null === state.id && (APPLICATION_STATE_INSTALLING === state.state.state || APPLICATION_STATE_STARTING === state.state.state || APPLICATION_STATE_RELOADING === state.state.state || APPLICATION_STATE_RESTARTING === state.state.state || APPLICATION_STATE_STOPPING === state.state.state)) {
    state.id = setTimeout(refresh_state, 1000)
  }

  state.loading = false
}

async function refresh_config(): Promise<void> {
  const cr = await v2ray_get_config()
  if (0 !== cr.code) {
    window.$message.error(cr.message)

    return
  }

  state.config = cr.data
}

async function refresh_state(): Promise<void> {
  const response = await v2ray_get_state()
  if (0 === response.code) {
    state.state = response.data

    if (APPLICATION_STATE_INSTALLING === state.state.state || APPLICATION_STATE_STARTING === state.state.state || APPLICATION_STATE_RESTARTING === state.state.state || APPLICATION_STATE_RELOADING === state.state.state || APPLICATION_STATE_STOPPING === state.state.state) {
      state.id = setTimeout(refresh_state, 1000)
    }
  }
}

async function start(): Promise<void> {
  if (APPLICATION_STATE_INSTALLED !== state.state.state && APPLICATION_STATE_RUN_ERROR !== state.state.state && APPLICATION_STATE_STOPPED != state.state.state) {
    window.$message.warning('V2ray应用当前状态不可启动')

    return
  }

  state.starting = true
  const response = await v2ray_start()
  state.starting = false

  if (0 !== response.code) {
    window.$message.error(response.message)

    return
  }

  window.$message.success('V2ray应用正在启动')
  await refresh_state()
}

async function restart(): Promise<void> {
  if (APPLICATION_STATE_RUNNING !== state.state.state) {
    window.$message.warning('V2ray应用当前状态不可重启')

    return
  }

  state.restarting = true
  const response = await v2ray_restart()
  state.restarting = false

  if (0 !== response.code) {
    window.$message.error(response.message)

    return
  }

  window.$message.success('V2ray应用正在重启')
  await refresh_state()
}

async function stop(): Promise<void> {
  if (APPLICATION_STATE_RUNNING !== state.state.state) {
    window.$message.warning('V2ray应用当前状态不可停止')

    return
  }

  state.stopping = true
  const response = await v2ray_stop()
  state.stopping = false

  if (0 !== response.code) {
    window.$message.error(response.message)

    return
  }

  window.$message.success('V2ray应用正在停止')
  await refresh_state()
}

async function show_qrcode(inbound: Bound): Promise<void> {
  if ('vmess' === inbound.protocol) {
    inbounds.vmess = new_v2ray_inbound_empty_vmess()
    inbounds.vmess.id = inbound.id
    inbounds.vmess.tag = inbound.tag
    inbounds.vmess.inbound_listen = inbound.inbound.listen
    inbounds.vmess.inbound_port = inbound.inbound.port
    inbounds.vmess.disable_insecure_encryption = inbound.vmess.inbound.disable_insecure_encryption
    inbounds.vmess.clients = inbound.vmess.inbound.clients
    inbounds.vmess.stream_settings = inbound.stream_settings

    modals.qrcode = true
  }
}

async function edit_inbound(inbound: Bound): Promise<void> {
  switch (inbound.protocol) {
    case 'vmess':
      inbounds.vmess = new_v2ray_inbound_empty_vmess()
      inbounds.vmess.id = inbound.id
      inbounds.vmess.tag = inbound.tag
      inbounds.vmess.inbound_listen = inbound.inbound.listen
      inbounds.vmess.inbound_port = inbound.inbound.port
      inbounds.vmess.disable_insecure_encryption = inbound.vmess.inbound.disable_insecure_encryption
      inbounds.vmess.clients = inbound.vmess.inbound.clients
      inbounds.vmess.stream_settings = inbound.stream_settings

      modals.inbound.vmess = true
      break
  }
}

async function remove_inbound(inbound: Bound): Promise<void> {
  inbound.removing = true
  const response = await v2ray_remove_inbound(inbound.id)
  inbound.removing = false

  if (0 !== response.code) {
    window.$message.error(response.message)

    return
  }

  window.$message.success('移除成功')
  await refresh_config()
}

async function edit_outbound(outbound: Bound): Promise<void> {
  switch (outbound.protocol) {
    case 'freedom':
      outbounds.freedom = new_v2ray_outbound_freedom()
      outbounds.freedom.id = outbound.id
      outbounds.freedom.tag = outbound.tag
      outbounds.freedom.outbound_send_through = outbound.outbound.send_through
      outbounds.freedom.domain_strategy = outbound.freedom.domain_strategy
      outbounds.freedom.redirect = outbound.freedom.redirect
      outbounds.freedom.user_level = outbound.freedom.user_level
      outbounds.freedom.stream_settings = outbound.stream_settings

      modals.outbound.freedom = true
      break
    case 'vmess':
      outbounds.vmess.id = outbound.id
      outbounds.vmess.tag = outbound.tag
      outbounds.vmess.outbound_send_through = outbound.outbound.send_through
      outbounds.vmess.stream_settings = outbound.stream_settings
      outbounds.vmess.vnext_list = outbound.vmess.outbound.vnext

      modals.outbound.vmess = true
      break
  }
}

async function remove_outbound(outbound: Bound): Promise<void> {
  outbound.removing = true
  const response = await v2ray_remove_outbound(outbound.id)
  outbound.removing = false

  if (0 !== response.code) {
    window.$message.error(response.message)

    return
  }

  window.$message.success('移除成功')
  await refresh_config()
}
</script>

<template>
  <div class='content-wrap'>
    <n-space vertical>
      <n-divider>应用状态管理</n-divider>
      <div>
        <template v-if='state.loading'>
          <n-skeleton height='25px' width='100%' />
        </template>
        <template v-else>
          <n-space :wrap-item='false' align='center' justify='space-between'>
            <div class='flex-max'>
              <n-space :wrap-item='false' align='center'>
                <div>{{ state.state.version }}</div>
                <div>{{ APPLICATION_STATE_NAMES[state.state.state] }}</div>
                <div v-if='APPLICATION_STATE_INSTALLING === state.state.state || APPLICATION_STATE_INSTALL_FAILURE === state.state.state' class='flex-max'>
                  <n-progress :percentage='state.state.progress' :show-indicator='false' status='success' type='line' />
                </div>
              </n-space>
            </div>
            <div>
              <n-space align='center'>
                <n-button v-if='APPLICATION_STATE_INSTALLED === state.state.state || APPLICATION_STATE_RUN_ERROR === state.state.state || APPLICATION_STATE_STOPPED === state.state.state || APPLICATION_STATE_STARTING === state.state.state' :disabled='APPLICATION_STATE_STARTING === state.state.state' :loading='state.starting' size='small' type='primary'
                          @click='start'>启动
                </n-button>
                <template v-if='APPLICATION_STATE_RUNNING === state.state.state || APPLICATION_STATE_RESTARTING === state.state.state || APPLICATION_STATE_STOPPING === state.state.state'>
                  <n-button :disabled='APPLICATION_STATE_RESTARTING === state.state.state || APPLICATION_STATE_STOPPING === state.state.state' :loading='state.restarting' size='small' type='warning' @click='restart'>重启</n-button>
                  <n-button :disabled='APPLICATION_STATE_RESTARTING === state.state.state || APPLICATION_STATE_STOPPING === state.state.state' :loading='state.stopping' size='small' type='error' @click='stop'>停止</n-button>
                </template>
              </n-space>
            </div>
          </n-space>
        </template>
      </div>
      <n-divider>入站协议配置</n-divider>
      <template v-if='state.loading || undefined == state.config'>
        <n-skeleton height='25px' width='100%' />
        <n-skeleton height='25px' width='100%' />
        <n-skeleton height='25px' width='100%' />
      </template>
      <template v-else>
        <template v-for='(inbound, index) in state.config.inbounds' :key='index'>
          <div :data-index='index'>
            <n-space :wrap-item='false' align='center'>
              <div class='flex-max'>
                <n-space align='center'>
                  <div style='width: 120px;'>协议: {{ inbound.protocol.toUpperCase() }}</div>
                  <div style='width: 360px;'>标签: {{ inbound.tag ? inbound.tag : '-' }}</div>
                  <div style='width: 240px;'>自定义传输配置: {{ inbound.stream_settings.enable ? '是' : '否' }}</div>
                  <div v-if='inbound.stream_settings.enable'>传输类型: {{ { 'tcp': 'TCP', 'kcp': 'KCP', 'ws': 'Websocket', 'domainsocket': 'DomainSocket', 'http': 'HTTP2', 'quic': 'Quic' }[inbound.stream_settings.network] }}</div>
                </n-space>
              </div>
              <div>
                <n-space align='center'>
                  <!--                    <template v-if='inbound.stream_settings.enable && "ws" === inbound.stream_settings.network'>-->
                  <!--                      <n-button size='small' type='primary'>添加站点</n-button>-->
                  <!--                      <n-button size='small' type='primary'>设置站点</n-button>-->
                  <!--                    </template>-->
                  <n-button v-if='"vmess" === inbound.protocol' size='small' type='primary' @click='show_qrcode(inbound)'>二维码</n-button>
                  <n-button size='small' type='primary' @click='edit_inbound(inbound)'>编辑</n-button>
                  <n-button :loading='inbound.removing' size='small' type='error' @click='remove_inbound(inbound)'>移除</n-button>
                </n-space>
              </div>
            </n-space>
          </div>
        </template>
        <div>
          <n-space :wrap-item='false' align='center'>
            <div class='flex-max'>
              <n-button class='width-max' size='small' type='primary' @click='inbounds.vmess = new_v2ray_inbound_empty_vmess(); modals.inbound.vmess = true'>添加VMess协议</n-button>
            </div>
          </n-space>
        </div>
      </template>
      <n-divider>出站协议配置</n-divider>
      <template v-if='state.loading || undefined === state.config'>
        <n-skeleton height='25px' width='100%' />
        <n-skeleton height='25px' width='100%' />
        <n-skeleton height='25px' width='100%' />
      </template>
      <template v-else>
        <template v-for='(outbound, index) in state.config.outbounds' :key='index'>
          <div :data-index='index'>
            <n-space :wrap-item='false' align='center'>
              <div class='flex-max'>
                <n-space align='center'>
                  <div style='width: 120px;'>协议: {{ outbound.protocol.toUpperCase() }}</div>
                  <div style='width: 360px;'>标签: {{ outbound.tag ? outbound.tag : '-' }}</div>
                </n-space>
              </div>
              <div>
                <n-space align='center'>
                  <n-button size='small' type='primary' @click='edit_outbound(outbound)'>编辑</n-button>
                  <n-button :loading='outbound.removing' size='small' type='error' @click='remove_outbound(outbound)'>移除</n-button>
                </n-space>
              </div>
            </n-space>
          </div>
        </template>
        <div>
          <n-space :wrap-item='false' align='center'>
            <div class='flex-max'>
              <n-button class='width-max' size='small' type='primary' @click='outbounds.vmess = new_v2ray_outbound_vmess(); modals.outbound.vmess = true'>添加VMess协议</n-button>
            </div>
            <div class='flex-max'>
              <n-button class='width-max' size='small' type='primary' @click='outbounds.freedom = new_v2ray_outbound_freedom(); modals.outbound.freedom = true'>添加Freedom协议</n-button>
            </div>
          </n-space>
        </div>
      </template>
    </n-space>
  </div>
  <ApplicationV2rayInboundVMess v-model:show='modals.inbound.vmess' :protocol='inbounds.vmess' @success='refresh_config' />
  <ApplicationV2rayOutboundFreedom v-model:show='modals.outbound.freedom' :protocol='outbounds.freedom' @success='refresh_config' />
  <ApplicationV2rayOutboundVMess v-model:show='modals.outbound.vmess' :protocol='outbounds.vmess' @success='refresh_config' />
  <ApplicationV2rayVMessQRCode v-model:show='modals.qrcode' :protocol='inbounds.vmess' />
</template>

<style scoped>

</style>
